------------------------------------------------------------------------------
--  Copyright (c) 2020 by Paul Scherrer Institute, Switzerland
--  All rights reserved.
--  Authors: Jonas Purtschert
--
--  Description: fw_version_id with axi interface
------------------------------------------------------------------------------

------------------------------------------------------------------------------
-- Libraries
------------------------------------------------------------------------------

library ieee;
  use ieee.std_logic_1164.all;
  use ieee.numeric_std.all;

library work;
  use work.psi_common_math_pkg.all;
  use work.psi_common_array_pkg.all;

------------------------------------------------------------------------------
-- Entity
------------------------------------------------------------------------------  
entity fw_version_id_axi is
  generic
  (
    C_ID_FACILITY            : string  := "FACILITY";
    C_ID_PROJECT             : string  := "PROJECT";
    C_REV_PINS               : boolean  := FALSE;

    -- AXI Parameters
    C_S00_AXI_ID_WIDTH       : integer := 1;                 -- Width of ID for for write address, write data, read address and read data
    C_S_AXI_ADDR_WIDTH       : integer := 9
  );
  port
  (
    -----------------------------------------------------------------------------
    -- Parameters, connecting to top level
    -----------------------------------------------------------------------------
    param_fw_git_version_i    : in  std_logic_vector(255 downto 0) := (others=>'0');
    param_fw_build_datetime_i : in  std_logic_vector(159 downto 0) := (others=>'0');
    --param_fw_build_date_i  : in  std_logic_vector(31 downto 0) := (others=>'0');
    --param_fw_build_time_i  : in  std_logic_vector(31 downto 0) := (others=>'0');

    -----------------------------------------------------------------------------
    -- External HW Rev Pins
    -----------------------------------------------------------------------------
    rev_pins_i    : in std_logic_vector(31 downto 0) := (others=>'0');

    -----------------------------------------------------------------------------
    -- Axi Slave Bus Interface
    -----------------------------------------------------------------------------
    -- System
    s00_axi_aclk                : in    std_logic;                                             -- Global Clock Signal
    s00_axi_aresetn             : in    std_logic;                                             -- Global Reset Signal. This signal is low active.
    -- Read address channel
    s00_axi_arid                : in    std_logic_vector(C_S00_AXI_ID_WIDTH-1   downto 0);     -- Read address ID. This signal is the identification tag for the read address group of signals.
    s00_axi_araddr              : in    std_logic_vector(C_S_AXI_ADDR_WIDTH-1  downto 0);                          -- Read address. This signal indicates the initial address of a read burst transaction.
    s00_axi_arlen               : in    std_logic_vector(7 downto 0);                          -- Burst length. The burst length gives the exact number of transfers in a burst
    s00_axi_arsize              : in    std_logic_vector(2 downto 0);                          -- Burst size. This signal indicates the size of each transfer in the burst
    s00_axi_arburst             : in    std_logic_vector(1 downto 0);                          -- Burst type. The burst type and the size information, determine how the address for each transfer within the burst is calculated.
    s00_axi_arlock              : in    std_logic;                                             -- Lock type. Provides additional information about the atomic characteristics of the transfer.
    s00_axi_arcache             : in    std_logic_vector(3 downto 0);                          -- Memory type. This signal indicates how transactions are required to progress through a system.
    s00_axi_arprot              : in    std_logic_vector(2 downto 0);                          -- Protection type. This signal indicates the privilege and security level of the transaction, and whether the transaction is a data access or an instruction access.
    s00_axi_arvalid             : in    std_logic;                                             -- Write address valid. This signal indicates that the channel is signaling valid read address and control information.
    s00_axi_arready             : out   std_logic;                                             -- Read address ready. This signal indicates that the slave is ready to accept an address and associated control signals.
    -- Read data channel
    s00_axi_rid                 : out   std_logic_vector(C_S00_AXI_ID_WIDTH-1 downto 0);       -- Read ID tag. This signal is the identification tag for the read data group of signals generated by the slave.
    s00_axi_rdata               : out   std_logic_vector(31 downto 0);                         -- Read Data
    s00_axi_rresp               : out   std_logic_vector(1 downto 0);                          -- Read response. This signal indicates the status of the read transfer.
    s00_axi_rlast               : out   std_logic;                                             -- Read last. This signal indicates the last transfer in a read burst.
    s00_axi_rvalid              : out   std_logic;                                             -- Read valid. This signal indicates that the channel is signaling the required read data.
    s00_axi_rready              : in    std_logic;                                             -- Read ready. This signal indicates that the master can accept the read data and response information.
    -- Write address channel
    s00_axi_awid                : in    std_logic_vector(C_S00_AXI_ID_WIDTH-1  downto 0);     -- Write Address ID
    s00_axi_awaddr              : in    std_logic_vector(C_S_AXI_ADDR_WIDTH-1  downto 0);                          -- Write address
    s00_axi_awlen               : in    std_logic_vector(7 downto 0);                          -- Burst length. The burst length gives the exact number of transfers in a burst
    s00_axi_awsize              : in    std_logic_vector(2 downto 0);                          -- Burst size. This signal indicates the size of each transfer in the burst
    s00_axi_awburst             : in    std_logic_vector(1 downto 0);                          -- Burst type. The burst type and the size information, determine how the address for each transfer within the burst is calculated.
    s00_axi_awlock              : in    std_logic;                                             -- Lock type. Provides additional information about the atomic characteristics of the transfer.
    s00_axi_awcache             : in    std_logic_vector(3 downto 0);                          -- Memory type. This signal indicates how transactions are required to progress through a system.
    s00_axi_awprot              : in    std_logic_vector(2 downto 0);                          -- Protection type. This signal indicates the privilege and security level of the transaction, and whether the transaction is a data access or an instruction access.
    s00_axi_awvalid             : in    std_logic;                                             -- Write address valid. This signal indicates that the channel is signaling valid write address and control information.
    s00_axi_awready             : out   std_logic;                                             -- Write address ready. This signal indicates that the slave is ready to accept an address and associated control signals.
    -- Write data channel
    s00_axi_wdata               : in    std_logic_vector(31    downto 0);                      -- Write Data
    s00_axi_wstrb               : in    std_logic_vector(3 downto 0);                          -- Write strobes. This signal indicates which byte lanes hold valid data. There is one write strobe bit for each eight bits of the write data bus.
    s00_axi_wlast               : in    std_logic;                                             -- Write last. This signal indicates the last transfer in a write burst.
    s00_axi_wvalid              : in    std_logic;                                             -- Write valid. This signal indicates that valid write data and strobes are available.
    s00_axi_wready              : out   std_logic;                                             -- Write ready. This signal indicates that the slave can accept the write data.
    -- Write response channel
    s00_axi_bid                 : out   std_logic_vector(C_S00_AXI_ID_WIDTH-1 downto 0);       -- Response ID tag. This signal is the ID tag of the write response.
    s00_axi_bresp               : out   std_logic_vector(1 downto 0);                          -- Write response. This signal indicates the status of the write transaction.
    s00_axi_bvalid              : out   std_logic;                                             -- Write response valid. This signal indicates that the channel is signaling a valid write response.
    s00_axi_bready              : in    std_logic                                              -- Response ready. This signal indicates that the master can accept a write response.    
  );

end entity fw_version_id_axi;

------------------------------------------------------------------------------
-- Architecture section
------------------------------------------------------------------------------

architecture rtl of fw_version_id_axi is 

  --------------------------
  -- Functions
  --------------------------
  function str2slv( s : string; len : integer)
    return std_logic_vector 
    is
      --variable r : std_logic_vector( s'length * 8 - 1 downto 0) ;
      variable r : std_logic_vector( len - 1 downto 0) ;
    begin
      for i in 1 to s'high loop
        r(i * 8 - 1 downto (i - 1) * 8) := std_logic_vector( to_unsigned( character'pos(s(i)) , 8 ) ) ;
      end loop;
      return r;
    end function;

  --------------------------
  -- Constants
  --------------------------
  -- Array of desired number of chip enables for each address range
  constant USER_SLV_NUM_REG               : integer := 32; 
  constant RAM_SIZE_DWORD                 : integer := 5*16; -- Number of 32-bit RAM entries

  --------------------------
  -- Signals
  --------------------------
  -- IP Interconnect (IPIC) signal declarations
  signal reg_rd                  : std_logic_vector(USER_SLV_NUM_REG-1 downto  0);
  signal reg_rdata               : t_aslv32(0 to USER_SLV_NUM_REG-1) := (others => (others => '0'));
  signal reg_wr                  : std_logic_vector(USER_SLV_NUM_REG-1 downto  0);
  signal reg_wdata               : t_aslv32(0 to USER_SLV_NUM_REG-1);  

  signal mem_addr                : std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto  0);
  signal mem_wr                  : std_logic_vector( 3 downto  0);
  signal mem_wr_any              : std_logic;
  signal mem_wdata               : std_logic_vector(31 downto  0);
  signal mem_rdata               : std_logic_vector(31 downto  0);

  signal bram_addr               : std_logic_vector(log2ceil(RAM_SIZE_DWORD)-1 downto 0); -- word address

  --signal facility                : std_logic_vector(127 downto 0) := str2slv(C_ID_FACILITY'length * 8 - 1 downto 0);
  signal facility                : std_logic_vector(127 downto 0) := str2slv(C_ID_FACILITY, 128);
  signal project                 : std_logic_vector(127 downto 0) := str2slv(C_ID_PROJECT, 128);
  signal PL_descriptor           : std_logic_vector(63 downto 0) := str2slv("PL", 64);
  signal hw_rev                  : std_logic_vector(31 downto 0) := (others=>'0');

begin

------------------------------------------------------------------------------
-- Components:
------------------------------------------------------------------------------

   -----------------------------------------------------------------------------
   -- AXI decode instance
   -----------------------------------------------------------------------------
   axi_slave_reg_inst : entity work.psi_common_axi_slave_ipif
   generic map
   (
      -- Users parameters
      num_reg_g                    => USER_SLV_NUM_REG,
      use_mem_g                    => true,
      -- Parameters of Axi Slave Bus Interface
      axi_id_width_g                => C_S00_AXI_ID_WIDTH,
      axi_addr_width_g              => C_S_AXI_ADDR_WIDTH
   )
   port map
   (
      --------------------------------------------------------------------------
      -- Axi Slave Bus Interface
      --------------------------------------------------------------------------
      -- System
      s_axi_aclk                  => s00_axi_aclk,
      s_axi_aresetn               => s00_axi_aresetn,
      -- Read address channel
      s_axi_arid                  => s00_axi_arid,
      s_axi_araddr                => s00_axi_araddr,
      s_axi_arlen                 => s00_axi_arlen,
      s_axi_arsize                => s00_axi_arsize,
      s_axi_arburst               => s00_axi_arburst,
      s_axi_arlock                => s00_axi_arlock,
      s_axi_arcache               => s00_axi_arcache,
      s_axi_arprot                => s00_axi_arprot,
      s_axi_arvalid               => s00_axi_arvalid,
      s_axi_arready               => s00_axi_arready,
      -- Read data channel
      s_axi_rid                   => s00_axi_rid,
      s_axi_rdata                 => s00_axi_rdata,
      s_axi_rresp                 => s00_axi_rresp,
      s_axi_rlast                 => s00_axi_rlast,
      s_axi_rvalid                => s00_axi_rvalid,
      s_axi_rready                => s00_axi_rready,
      -- Write address channel
      s_axi_awid                  => s00_axi_awid,
      s_axi_awaddr                => s00_axi_awaddr,
      s_axi_awlen                 => s00_axi_awlen,
      s_axi_awsize                => s00_axi_awsize,
      s_axi_awburst               => s00_axi_awburst,
      s_axi_awlock                => s00_axi_awlock,
      s_axi_awcache               => s00_axi_awcache,
      s_axi_awprot                => s00_axi_awprot,
      s_axi_awvalid               => s00_axi_awvalid,
      s_axi_awready               => s00_axi_awready,
      -- Write data channel
      s_axi_wdata                 => s00_axi_wdata,
      s_axi_wstrb                 => s00_axi_wstrb,
      s_axi_wlast                 => s00_axi_wlast,
      s_axi_wvalid                => s00_axi_wvalid,
      s_axi_wready                => s00_axi_wready,
      -- Write response channel
      s_axi_bid                   => s00_axi_bid,
      s_axi_bresp                 => s00_axi_bresp,
      s_axi_bvalid                => s00_axi_bvalid,
      s_axi_bready                => s00_axi_bready,
      --------------------------------------------------------------------------
      -- Register Interface
      --------------------------------------------------------------------------
      o_reg_rd                    => reg_rd,
      i_reg_rdata                 => reg_rdata,
      o_reg_wr                    => reg_wr,
      o_reg_wdata                 => reg_wdata,

      o_mem_addr                  => mem_addr,
      o_mem_wr                    => mem_wr,
      o_mem_wdata                 => mem_wdata,
      i_mem_rdata                 => mem_rdata
   );

    --------------------------------------------------------------------------
    -- AXI Register Map
    --------------------------------------------------------------------------

   proc_reg : process(s00_axi_aclk)
   begin
     if (rising_edge(s00_axi_aclk)) then
       -- external rev pins:
       if (C_REV_PINS = TRUE) then
         hw_rev <= rev_pins_i;
       else
         -- register based hw rev, written by software:
         if (reg_wr(8) = '1') then
           hw_rev <= reg_wdata(8);
         end if;
       end if;
     end if;

   end process;


    -- 0x000 : Facility
    gen_reg_facility: for i in 0 to 3 generate 
    reg_rdata(i+0) <= facility(i*32 +32-1 downto i*32);
    end generate;

    -- 0x010 : Project
    gen_reg_project: for i in 0 to 3 generate 
    reg_rdata(i+4) <= project(i*32 +32-1 downto i*32);
    end generate;

    -- 0x020 : HW Revision
    reg_rdata(8) <= hw_rev;

    reg_rdata(9)  <= (others=>'0'); -- reserved
    reg_rdata(10) <= (others=>'0'); -- reserved
    reg_rdata(11) <= (others=>'0'); -- reserved

    reg_rdata(12) <= (others=>'0'); -- reserved
    reg_rdata(13) <= (others=>'0'); -- reserved
    reg_rdata(14) <= (others=>'0'); -- reserved
    reg_rdata(15) <= (others=>'0'); -- reserved

    -- 0x40 ID0 - Descriptor PL
    gen_reg_descr: for i in 0 to 1 generate 
    reg_rdata(i+16) <= pl_descriptor(i*32 +32-1 downto i*32);
    end generate;

    -- 0x48 ID0 - Git Repo Version
    gen_reg_gitrev: for i in 0 to 7 generate 
      reg_rdata(i+18) <= param_fw_git_version_i(i*32 +32-1 downto i*32);
    end generate;

    -- 0x68 ID0 - Build Date/time:
    gen_reg_datetime: for i in 0 to 4 generate 
      reg_rdata(i+26) <= param_fw_build_datetime_i(i*32 +32-1 downto i*32);
    end generate;

    --reg_rdata(16) <= param_fw_build_date_i;
    --reg_rdata(17) <= param_fw_build_time_i;

   ---------------------------------------------------------------------------
   -- BRAM 
   ---------------------------------------------------------------------------
   mem_wr_any <= '1' when mem_wr /= "0000" else '0';
   bram_addr <= mem_addr(log2ceil(RAM_SIZE_DWORD)+1 downto 2); -- map axi byte address to word address

   bram_inst: entity work.psi_common_sp_ram_be
      generic map (
         depth_g        => RAM_SIZE_DWORD,
         width_g        => 32
      )
      port map (
         clk_i           => s00_axi_aclk,
         addr_i          => bram_addr,
         wr_i            => mem_wr_any,
         be_i            => mem_wr,
         dat_i           => mem_wdata,
         dat_o          => mem_rdata
      );

end rtl;

